﻿using SiMay.Sockets.UtilityHelper;
using System;
using System.Net.Sockets;

namespace SiMay.Sockets.Tcp.Awaitable
{
    /// <summary>
    /// SocketAsyncEventArgs(Socket异步操作)扩展
    /// </summary>
    public class SaeaExHelper
    {
        /// <summary>
        /// 开始一个异步操作来接受一个传入的连接尝试
        /// </summary>
        private static readonly Func<Socket, SaeaAwaiter, bool> ACCEPT = (s, a) => s.AcceptAsync(a.Saea);
        private static readonly Func<Socket, SaeaAwaiter, bool> CONNECT = (s, a) => s.ConnectAsync(a.Saea);
        private static readonly Func<Socket, SaeaAwaiter, bool> DISCONNECT = (s, a) => s.DisconnectAsync(a.Saea);
        private static readonly Func<Socket, SaeaAwaiter, bool> RECEIVE = (s, a) => s.ReceiveAsync(a.Saea);
        private static readonly Func<Socket, SaeaAwaiter, bool> SEND = (s, a) => s.SendAsync(a.Saea);

        /// <summary>
        /// 接受连接
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="awaiter"></param>
        /// <param name="callback"></param>
        public static void AcceptAsync(Socket socket, SaeaAwaiter awaiter, Action<SaeaAwaiter, SocketError> callback)
            => OperateAsync(socket, awaiter, ACCEPT, callback);

        /// <summary>
        /// 连接成功
        /// </summary>
        /// <param name="socket">Socket对象</param>
        /// <param name="awaiter"></param>
        /// <param name="callback">回调方法</param>
        public static void ConnectAsync(Socket socket, SaeaAwaiter awaiter, Action<SaeaAwaiter, SocketError> callback)
            => OperateAsync(socket, awaiter, CONNECT, callback);

        /// <summary>
        /// 断开连接
        /// </summary>
        /// <param name="socket">Socket对象</param>
        /// <param name="awaiter"></param>
        /// <param name="callback">回调方法</param>
        public static void DisonnectAsync(Socket socket, SaeaAwaiter awaiter, Action<SaeaAwaiter, SocketError> callback)
            => OperateAsync(socket, awaiter, DISCONNECT, callback);

        /// <summary>
        /// 收到数据
        /// </summary>
        /// <param name="socket">Socket对象</param>
        /// <param name="awaiter"></param>
        /// <param name="callback">回调方法</param>
        public static void ReceiveAsync(Socket socket, SaeaAwaiter awaiter, Action<SaeaAwaiter, SocketError> callback)
            => OperateAsync(socket, awaiter, RECEIVE, callback);

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="socket">Socket对象</param>
        /// <param name="awaiter"></param>
        /// <param name="callback">回调方法</param>
        public static void SendAsync(Socket socket, SaeaAwaiter awaiter, Action<SaeaAwaiter, SocketError> callback)
            => OperateAsync(socket, awaiter, SEND, callback);

        /// <summary>
        /// 异步操作回调
        /// </summary>
        /// <param name="socket">Socket对象</param>
        /// <param name="awaiter">异步操作对象</param>
        /// <param name="operation">异步操作方法</param>
        /// <param name="callback">回调方法</param>
        private static void OperateAsync(Socket socket, SaeaAwaiter awaiter, Func<Socket, SaeaAwaiter, bool> operation, Action<SaeaAwaiter, SocketError> callback)
        {
            if (socket == null)
                return;

            //try
            //{
            //清空回调方法
            awaiter.Reset();
            //替换回调方法
            awaiter.OnCompleted(callback);

            //调用Socket的异步方法，如果是I/O 操作挂起，操作完成时，将引发SaeaAwaiter对象的Saea的 Completed 事件
            bool willSyncCompleted = operation.Invoke(socket, awaiter);
            //如果是 I/O 操作同步完成，将不会 Completed 事件
            if (!willSyncCompleted)
            {
                //触发执行回调方法
                awaiter.CompletedHandler();
            }

            //}
            //catch (Exception ex)
            //{
            //    LogHelper.WriteLog("OperateAsync:" + ex.Message);
            //}

        }

    }
}
